
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;

using Swaf;
using Swaf.BizObj;

namespace Swaf.BizObj.basic
{
	[Serializable]
	public class FullBizObjList : BaseBizObjList,ISerializable
	{
		protected IList m_objs = new ArrayList();

		public FullBizObjList(string listName, IBizObjDefinition bizObjType)
			: base(listName, bizObjType)
		{
		}

		public FullBizObjList(XmlElement ele, string catalogName)
		{
			m_listName = "";
			XmlTextReader xmlIn = null;
			try
			{
				XmlNameTable nt = new NameTable();
				XmlNamespaceManager nsMgr = new XmlNamespaceManager(nt);
				XmlParserContext context = new XmlParserContext(nt, nsMgr, null, XmlSpace.None);
				xmlIn = new XmlTextReader(ele.OuterXml, XmlNodeType.Element, context);
				string rootNodeName = "";
				if (xmlIn.MoveToContent() == XmlNodeType.Element)
				{
					rootNodeName = xmlIn.Name;
					m_listName = rootNodeName;
					createFromStream(null, xmlIn, BaseBizObj.DefaultFieldDecoInfo);
				}
			}
			catch (Exception e)
			{
				throw (e);
			}
			finally
			{
				xmlIn.Close();
			}
		}

		public FullBizObjList(string listName, IBizObjDefinition objType, IBizObjSource source)
			: base(listName, objType)
		{
			m_source = source;
		}

		public FullBizObjList(System.Text.RegularExpressions.Match m, object[] extraInfo)
		{
			Swaf.BizObj.BizObjManager bizObjMgr = (Swaf.BizObj.BizObjManager)Application.currentApp.bizObjMgr;
			m_bizObjType = bizObjMgr.getBizObjDefinition(m.Groups[1].Value);
		}


		/// <summary>
		/// Creates a bizobj list by reconstructing from xml stream
		/// </summary>
		/// <param name="objType">If null, it will be set based on name of first child element in the xml list.</param>
		/// <param name="source"></param>
		/// <param name="xml"></param>
		public FullBizObjList(IBizObjDefinition objType, IBizObjSource source, XmlTextReader xml)
			: this(objType, source, xml, BaseBizObj.DefaultFieldDecoInfo)
		{
			//Intentionally left blank
		}

		public FullBizObjList(IBizObjDefinition objType, IBizObjSource source, XmlTextReader xml, string decoInfo)
			: base(source)
		{
			createFromStream(objType, xml, decoInfo);
		}

		public static IBizObjList createInstance(string listName, IBizObjDefinition objType)
		{
			IBizObjList objList = null;
			if (FullBizObj.EarlyBindFactory != null)
				objList = (IBizObjList)FullBizObj.EarlyBindFactory.
					createFromNickName(objType.Name + "List", listName, objType);
			else
				objList = new FullBizObjList(listName, objType);

			return objList;
		}

		public static IBizObjList createInstance(string listName, IBizObjDefinition objType, IBizObjSource source)
		{
			IBizObjList objList = null;
			if (FullBizObj.EarlyBindFactory != null)
				objList = (IBizObjList)FullBizObj.EarlyBindFactory.
					createFromNickName(objType.Name + "List", listName, objType, source);
			else
				objList = new FullBizObjList(listName, objType, source);

			return objList;
		}

		public static IBizObjList createInstance(System.Text.RegularExpressions.Match m, object[] extraInfo)
		{
			IBizObjList objList = null;
			if (FullBizObj.EarlyBindFactory != null)
				objList = (IBizObjList)FullBizObj.EarlyBindFactory.
					createFromNickName(m.Groups[1].Value + "List", m, extraInfo);
			else
				objList = new FullBizObjList(m, extraInfo);

			return objList;
		}

		public static IBizObjList createInstance(IBizObjDefinition objType, IBizObjSource source, XmlTextReader xml)
		{
			return createInstance(objType, source, xml, BaseBizObj.DefaultFieldDecoInfo);
		}
		public static IBizObjList createInstance(IBizObjDefinition objType, IBizObjSource source, XmlTextReader xml, string extraInfo)
		{
			IBizObjList objList = null;
			if (FullBizObj.EarlyBindFactory != null)
			{
				FullBizObjList tempList = new FullBizObjList(objType, source, xml);
				FullBizObjList temp2 = (FullBizObjList)FullBizObj.EarlyBindFactory.
					createFromNickName(tempList.objectType.Name + "List", tempList.Name, tempList.objectType);
				temp2.m_objs = tempList.m_objs;
				objList = temp2;

			}
			else
				objList = new FullBizObjList(objType, source, xml, extraInfo);

			return objList;
		}

		protected void createFromStream(IBizObjDefinition objType, XmlTextReader xml, string decoInfo)
		{
			Debug.Assert(xml != null);

			Swaf.BizObj.BizObjManager bizObjMgr = (Swaf.BizObj.BizObjManager)Application.currentApp.bizObjMgr;
			m_bizObjType = objType;

			if (xml.NodeType == XmlNodeType.Element)
			{
				m_listName = xml.Name;
				//We need to add a reference to the newly created list by name to its source.
				Source.AddList(this);
				string typeAttr = xml.GetAttribute("type");
				if (typeAttr != null && m_bizObjType == null)
					m_bizObjType = bizObjMgr.getBizObjDefinition(typeAttr);
				while (xml.Read())
				{
					if (xml.NodeType == XmlNodeType.Element)
					{
						try
						{
							if (m_bizObjType == null)
								m_bizObjType = bizObjMgr.getBizObjDefinition(xml.Name);
							//m_objs.Add(new FullBusinessObject("",m_bizObjType, xml));
							m_objs.Add(createBizObj("", xml, decoInfo));
						}
						catch (BadBizObjTypeException e)
						{
							//This exception should only be thrown when m_bizObjType is null and
							//the getBizObjInfo is called.  Once m_bizObjType is not null this should
							//never hapen on this call.

							//TODO: What if the list doesn't contain valid bizobj types, Should we throw an exception or just log?
							//Right now we move on and try with the next one
							xml.Skip();
						}
					}
					else if (xml.NodeType == XmlNodeType.EndElement)
					{
						//xml.ReadEndElement();
						break;
					}
				}
			}
		}

		public override int Add(object obj)
		{
			if (obj is IBizObj && ((IBizObj)obj).isKindOf(m_bizObjType.Name))
				return m_objs.Add(obj);
			else
			{
				//TODO: Adding a bad type to the list.  Should we throw an exception or log
				return -1;
			}
		}

		protected virtual IBizObj createBizObj()
		{
			return FullBizObj.createInstance(m_bizObjType);
		}

		protected virtual IBizObj createBizObj(string parentFieldName, XmlTextReader xml, string decoInfo)
		{
			return FullBizObj.createInstance(parentFieldName, m_bizObjType, xml, decoInfo);
		}

		#region IBizObjList Members

		public override IBizObj this[int index]
		{
			get
			{
				if (index < 0 || index >= numElements)
					throw new Exception("Out of range");
				return (IBizObj)m_objs[index];
			}
			set
			{
				m_objs[index] = value;
			}
		}

		public override IBizObj insertNew()
		{
			IBizObj newObj = createBizObj();
			lock (m_objs)
			{
				m_objs.Add(newObj);
			}
			return newObj;
		}

		public override int numElements
		{
			get
			{
				return m_objs.Count;
			}
		}

		public override IBizObj insertNewMakeCopy(IBizObj obj)
		{
			IBizObj newObj = (IBizObj)obj.Clone();
			lock (m_objs)
			{
				m_objs.Add(newObj);
			}
			return newObj;
		}

        public override void Insert(int index, object value)
        {
			if(value is IBizObj)
				m_objs.Insert(index, value);
        }

		public override IBizObjDefinition objectType
		{
			get
			{
				return m_bizObjType;
			}
		}

		public override IBizObjSource Source
		{
			get
			{
				if (m_source == null)
					m_source = new FullBizObjSource(this, "");
				return m_source;
			}
		}

		public override void removeAt(int index)
		{
			lock (m_objs)
			{
				if (index < 0 || index >= numElements)
					throw new Exception("Out of range");
				m_objs.RemoveAt(index);
			}
		}

        public override void Remove(object value)
        {
            lock(m_objs)
                m_objs.Remove(value);            
        }

		public override int IndexOf(object value)
		{
			return m_objs.IndexOf(value);
		}

		public override void refresh()
		{
		}

		public override IBizObjCursor createCursor()
		{
			return new FullBizObjCursor(this);
		}

		public override IBizObj search(string fieldList, object matchValue)
		{
			return search(fieldList, matchValue, false);
		}
		public override IBizObj search(string fieldList, object matchValue, bool findNearestMatch)
		{
			Debug.Assert(Source != null);
			StringBuilder buf = new StringBuilder(50);
			buf.Append(m_listName).Append(":").Append(fieldList);
			return this.Source.getObject(objectType.Name, buf.ToString(), matchValue, findNearestMatch);
		}

		public override void refreshIndexesFromBizObj(IBizObj insertedObj)
		{
			if (m_source != null)
			{
				IDictionary lists = ((FullBizObjSource)m_source).Lists;
				foreach (DictionaryEntry di in lists)
					if (!Cmn.IsEmpty(di.Key) && di.Value is IndexedFullBizObjList)
						((IndexedFullBizObjList)di.Value).addBizObj(insertedObj);
			}
		}


		public override string getXml(string name, bool setOnly, bool dirtyOnly, bool newOnly, bool getBasic, bool getObjs, bool getILists, bool getSysVals, System.Xml.XmlTextWriter xmlOut)
		{
			return getXml(name, BaseBizObj.DefaultFieldDecoInfo, setOnly, dirtyOnly, newOnly, getBasic, getObjs, getILists, getSysVals, xmlOut);
		}
		public override string getXml(string name, string decoInfo, bool setOnly, bool dirtyOnly, bool newOnly, bool getBasic, bool getObjs, bool getILists, bool getSysVals, System.Xml.XmlTextWriter xmlOut)
		{
			bool madeXmlOut = false;
			StringWriter strBuf = null;
			if (xmlOut == null)
			{
				strBuf = new StringWriter();
				xmlOut = new XmlTextWriter(strBuf);
				xmlOut.Formatting = Formatting.Indented;
				madeXmlOut = true;
			}
			if (name != "")
				xmlOut.WriteStartElement(name);
			if (getSysVals)
				xmlOut.WriteAttributeString("type", this.m_bizObjType.Name);

			if (m_objs.Count > 0 || !setOnly)
				for (int pos = 0; pos < m_objs.Count; ++pos)
				{
					IBizObj obj = (IBizObj)m_objs[pos];
					obj.getXml(null, decoInfo, setOnly, dirtyOnly, newOnly, getBasic, getObjs, getILists, getSysVals, xmlOut);
				}

			if (name != "")
				xmlOut.WriteEndElement();
			if (madeXmlOut)
			{
				xmlOut.Close();
				strBuf.Close();
				return strBuf.ToString();
			}
			return null;
		}

		protected FullBizObjList(FullBizObjList l)
		{
			ArrayList a = new ArrayList();
			a.AddRange(l.m_objs);
			this.m_objs = a;
			this.m_bizObjType = l.m_bizObjType;
		}
		public override void Clear()
		{
			if (m_objs != null)
			{
				m_objs.Clear();
			}
		}
		public override object Clone()
		{
			return new FullBizObjList(this);
		}

		#endregion
		public FullBizObjList(System.Runtime.Serialization.SerializationInfo info, StreamingContext context)
		{
			m_bizObjType = Application.globalApp.bizObjMgr.getDefinition(info.GetString("n"));
			m_listName = info.GetString("ln");
			m_objs = (IList)info.GetValue("v", typeof(System.Collections.ArrayList));
		}

		#region ISerializable Members

		public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, StreamingContext context)
		{
			info.AddValue("n", m_bizObjType.Name);
			info.AddValue("ln", m_listName);
			info.AddValue("v", m_objs);
		}

		#endregion
	}
}
